#include "ring_fifo.h"

#undef MIN
#define MIN(a,b) ((a) > (b)?(b):(a))

#undef RING_PARAMETER_VERIFY
#define RING_PARAMETER_VERIFY(expr) do {	\
	if(expr)								\
	{										\
		return RF_INVALID_PARAMETER;		\
	}										\
}while(0)

/*环形缓冲区相关结构体*/
struct ring_fifo_t {
	volatile uint32_t 	head;/*缓冲区头部*/
	volatile uint32_t 	tail;/*缓冲区尾部*/
	uint32_t 			size;/*缓冲区的大小*/
	uint8_t 			*dataBuf;/*指向缓冲区的指针*/
	uint32_t 			isDynamic;/*是否使用了动态内存*/
	enum ring_fifo_type type;/*fifo的类型*/
};

static inline bool is_power_of_2(uint32_t n);

static inline bool is_power_of_2(uint32_t n)
{
	return ((n != 0) && ((n & (n - 1)) == 0));
}

uint32_t ring_fifo_init(struct ring_fifo_t **__ring, uint8_t *pBuf, uint32_t size, enum ring_fifo_type type)
{
	uint32_t res = RF_SUCCESS;
	RING_PARAMETER_VERIFY((type != RF_TYPE_FRAME) && (type != RF_TYPE_STREAM));
	struct ring_fifo_t *_ring = NULL;
	if(!is_power_of_2(size)) { return RF_IS_NOT_POWER_OF_2; }

	_ring = (struct ring_fifo_t *)malloc(sizeof(struct ring_fifo_t));
	if(!_ring)
	{
		res = RF_MALLOC_FAILED;
		return res;
	}
	
	_ring->head = 0;
	_ring->tail = 0;
	_ring->size = size;
	if(pBuf)
	{
		_ring->dataBuf = pBuf;
		_ring->isDynamic = 0;
	}
	else
	{
		_ring->dataBuf = (uint8_t *)malloc(_ring->size * sizeof(*_ring->dataBuf));
		if(!_ring->dataBuf)
		{
			free(_ring);
			_ring = NULL;
			
			res = RF_MALLOC_FAILED;
			return res;
		}
		_ring->isDynamic = 1;
	}
	memset(_ring->dataBuf, 0, _ring->size * sizeof(*_ring->dataBuf));

	_ring->type = type;

	*__ring = _ring;

	return res;
}

uint32_t ring_fifo_write(struct ring_fifo_t *_ring, const uint8_t *pBuf, uint16_t len)
{
	uint32_t res = RF_SUCCESS;
	uint16_t frame_len = 0;

	frame_len = len;

	RING_PARAMETER_VERIFY(_ring == NULL);
	RING_PARAMETER_VERIFY(pBuf == NULL);
	RING_PARAMETER_VERIFY(len == 0);

	switch(_ring->type)
	{
		case RF_TYPE_FRAME:
		//如果不能存下此帧，则舍弃
		if(len + sizeof(len) > _ring->size - (_ring->tail - _ring->head)) { return RF_FULL; }

		/*
		*写入帧长
		*/
		_ring->dataBuf[(_ring->tail++) & (_ring->size - 1)] = (len >> 8) & 0xff;
		_ring->dataBuf[(_ring->tail++) & (_ring->size - 1)] = (len >> 0) & 0xff;
		break;
		case RF_TYPE_STREAM:
		//缓冲区满
		if(1 > _ring->size - (_ring->tail - _ring->head)) { return RF_FULL; }
		//如果不能全部存下，则丢掉多余数据
		frame_len = len > _ring->size - (_ring->tail - _ring->head) ? _ring->size - (_ring->tail - _ring->head) : len;
		break;
	}

	//计算写入位置
	uint32_t off = _ring->tail & (_ring->size - 1);
	/*
	*写入数据
	*如果剩余空间未跨首尾相接的地方，则一次写入，否则分两次写入
	*/
	uint32_t min = MIN(frame_len, _ring->size - off);
	memcpy(&(_ring->dataBuf[off]), pBuf, min);
	memcpy(&(_ring->dataBuf[0]), pBuf + min, frame_len - min);
	_ring->tail += frame_len;

	return res;
}

uint32_t ring_fifo_read(struct ring_fifo_t *_ring, uint8_t *pBuf, uint16_t len, uint16_t *retLen)
{
	uint32_t res = RF_SUCCESS;
	uint16_t frame_len = 0;

	*retLen = 0;

	RING_PARAMETER_VERIFY(_ring == NULL);
	RING_PARAMETER_VERIFY(pBuf == NULL);
	RING_PARAMETER_VERIFY(len == 0);

	//无数据可读
	if(_ring->tail == _ring->head) { return RF_EMPTY; }

	switch(_ring->type)
	{
		case RF_TYPE_FRAME:
		/*
		*读取帧长
		*/
		frame_len |= (_ring->dataBuf[(_ring->head++) & (_ring->size - 1)] << 8) & 0xffff;
		frame_len |= (_ring->dataBuf[(_ring->head++) & (_ring->size - 1)] << 0) & 0xffff;
		//内存越界
		if(frame_len > len) { return RF_READ_BUFFER_TOO_SMALL; }
		break;
		case RF_TYPE_STREAM:
		//如果可读数据长度大于要读取的长度，则读取指定长度，否则读取可读数据长度
		frame_len = _ring->tail - _ring->head > len ? len : _ring->tail - _ring->head;
		break;
	}

	//计算读取位置
	uint32_t off = _ring->head & (_ring->size - 1);
	/*
	*读取数据
	*如果剩余空间未跨首尾相接的地方，则一次读出，否则分两次读出
	*/
	uint32_t min = MIN(frame_len, _ring->size - off);
	memcpy(pBuf, &(_ring->dataBuf[off]), min);
	memcpy(pBuf + min, &(_ring->dataBuf[0]), frame_len - min);
	_ring->head += frame_len;

	*retLen = frame_len;

	return res;
}

void ring_fifo_destroy(struct ring_fifo_t *_ring)
{
	if(_ring->isDynamic)
	{
		free(_ring->dataBuf);
		_ring->dataBuf = NULL;
	}
	
	free(_ring);
	_ring = NULL;
}

bool ring_fifo_is_full(struct ring_fifo_t *_ring)
{
	switch(_ring->type)
	{
		case RF_TYPE_FRAME:
		//不适用
		return false;
		break;
		case RF_TYPE_STREAM:
		if(1 > _ring->size - (_ring->tail - _ring->head)) { return true; }
		break;
	}

	return false;
}

bool ring_fifo_is_empty(struct ring_fifo_t *_ring)
{
	if(_ring->tail == _ring->head) { return true; }

	return false;
}
